﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using WinAPI32Library;
using System.IO;

namespace CreateProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            // createprocess vars
            Kernel32.PROCESS_INFORMATION pi = new Kernel32.PROCESS_INFORMATION();
            Kernel32.STARTUP_INFO si = new Kernel32.STARTUP_INFO();

            // file path
            string file = @"D:\MSVSProjects\Erofeev TFS\TestCommandLine\bin\Debug\TestCommandLine.exe";

            // getexitcode var
            uint
                exitCode = 0;

            // processtimes vars
            long
                _creation = 0,
                _exit = 0,
                _kernel = 0,
                _user = 0;

            // all priority classes 
            uint[] priorityClass = {
                                       (uint)Kernel32.ProcessPriorityClass.IDLE_PRIORITY_CLASS,
                                       (uint)Kernel32.ProcessPriorityClass.BELOW_NORMAL_PRIORITY_CLASS,
                                       (uint)Kernel32.ProcessPriorityClass.NORMAL_PRIORITY_CLASS,
                                       (uint)Kernel32.ProcessPriorityClass.ABOVE_NORMAL_PRIORITY_CLASS,
                                       (uint)Kernel32.ProcessPriorityClass.HIGH_PRIORITY_CLASS,
                                       (uint)Kernel32.ProcessPriorityClass.REALTIME_PRIORITY_CLASS
                                   };
            int
                // how many process priorities will be run through
                processesCount = priorityClass.Length,
                // number of created process
                count = 0;

            // if log file exists, delete it
            if (File.Exists("threads.txt"))
                File.Delete("threads.txt");

            // counts process execution time
            Stopwatch sw = new Stopwatch();
            sw.Start();

            // run through all process priorities
            for (int i = 0; i < processesCount; i++)
            {
                // amount of thread priorities to be run through
                // max amount 7 thread priorities
                int threadPriorities = 7;
                // run through thread priorities
                // x - first thread
                // y - second thread
                // z - third thread
                for (int x = 0; x < threadPriorities; x++)
                    for (int y = 0; y < threadPriorities; y++)
                        for (int z = 0; z < threadPriorities; z++)
                        {
                            // params to push to process
                            string prms = " " + x + " " + y + " " + z;
                            // create process
                            Kernel32.CreateProcess(
                                file,
                                prms,
                                IntPtr.Zero,
                                IntPtr.Zero,
                                false,
                                priorityClass[i] | (uint)Kernel32.CreationFlags.CREATE_NO_WINDOW,
                                IntPtr.Zero,
                                null,
                                ref si,
                                out pi);

                            // increment process counter
                            count++;
                            // print to console data
                            echo(count, false);
                            // print process descriptor
                            echo(" - PID (" + i + "): " + pi.hProcess, false);
                            // print process priority
                            echo(", priorClass: " + Kernel32.GetPriorityClass(pi.hProcess) + "/" + priorityClass[i], false);
                            // get propcess exit code
                            Kernel32.GetExitCodeProcess(pi.hProcess, out exitCode);
                            // get creation and exit times of process 
                            Kernel32.GetProcessTimes(pi.hProcess, out _creation, out _exit, out _kernel, out _user);
                            // wait while process is still alive and exit tiome is still 0,
                            while (exitCode == 259 || _exit == 0)
                            {
                                // get exit process code
                                Kernel32.GetExitCodeProcess(pi.hProcess, out exitCode);
                                // get process exit time
                                Kernel32.GetProcessTimes(pi.hProcess, out _creation, out _exit, out _kernel, out _user);
                            }
                            echo(", e-code: " + exitCode, false);
                            // get creation and exit time of process
                            Kernel32.GetProcessTimes(pi.hProcess, out _creation, out _exit, out _kernel, out _user);
                            // calculate process time
                            TimeSpan time = Kernel32.Elapsed(_creation, _exit);
                            // print to console
                            echo(", elapsed: " + time.Milliseconds);
                            // create steramwriter to write data to file
                            StreamWriter w = new StreamWriter("threads.txt", true);
                            // write data to file
                            w.WriteLine("Process: " + time.Milliseconds + " ms");
                            w.WriteLine("-====-");
                            // close file
                            w.Close();
                            // close process handle
                            Kernel32.CloseHandle(pi.hProcess);
                            // collect garbage
                            GC.Collect();
                        }
            }

            // stop timer
            sw.Stop();
            echo("Stopwatch: " + sw.Elapsed);

            // wait for key to be pressed
            Console.ReadKey(true);
        }

        public static void echo(dynamic s, bool newline = true)
        {
            if (newline)
                Console.WriteLine(s);
            else
                Console.Write(s);
        }
    }
}
